应用设计模式的核心目标:应对变化,提高复用。
什么地方应用:寻找变化点,在变化点应用模式。
什么时间应用:一般没有一步到位的设计模式,而是重构到模式,重构技法:
静态→动态;
早绑定→晚绑定;
继承→组合;
编译时依赖→运行时依赖;
紧耦合→松耦合;
根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素)中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。
简单说就是面对较复杂、大型系统,考虑对象的创建、对象之间的组合与通信。
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。就像我们去商场购买商品时,不需要知道商品是怎么生产出来一样,因为它们由专门的厂商生产。
另一种细分的标识:① 对象创建;② 对象性能;③ 单一职责;④ 组件协作;⑤ 接口隔离;⑥ 状态变化;⑦ 数据结构;⑧ 行为变化; ⑨ 领域问题
1 简单工厂模式(Factory Pattern)①
2 工厂方式模式(Factory Pattern)①
3 抽象工厂模式(Abstract Factory Pattern)①
4 单例模式(Singleton Pattern)[② 对象性能]
5 建造者模式(Builder Pattern)①
6 原型模式(Prototype Pattern)①
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。
由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。
7 适配器模式(Adapter Pattern)[⑤ 接口隔离]
8 桥接模式(Bridge Pattern)[③ 单一职责]
过滤器模式(Filter、Criteria Pattern)
9 组合模式(Composite Pattern)[⑦ 数据结构]
10 装饰器模式(Decorator Pattern)[③ 单一职责]
11 外观模式(Facade Pattern)[⑤ 接口隔离]
12 享元模式(Flyweight Pattern)[② 对象性能]
13 代理模式(Proxy Pattern)[⑤ 接口隔离]
这些设计模式特别关注对象之间的通信。
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。
14 责任链模式(Chain of Responsibility Pattern)[⑦ 数据结构]
15 命令模式(Command Pattern)⑧ 行为变化]
16 解释器模式(Interpreter Pattern)[⑨ 领域问题]
17 迭代器模式(Iterator Pattern)[⑦ 数据结构]
18 中介者模式(Mediator Pattern)[⑤ 接口隔离]
19 备忘录模式(Memento Pattern)[⑥ 状态变化]
20 观察者模式(Observer Pattern)[④ 组件协作]
21 状态模式(State Pattern)[⑥ 状态变化]
空对象模式(Null Object Pattern)
22 策略模式(Strategy Pattern)[④ 组件协作]
23 访问者模式(Visitor Pattern)[⑧ 行为变化]
24 模板模式(Template Pattern)[④ 组件协作]
《设计模式:可利用面向对象软件的基础》
可复用是设计模式的目标,变化是复用的天敌,如何抵御变化:
隔离变化、各类各司其职,由此需重新认识对象
1 从语言实现层面来看,对象封装了代码和数据;
2 从规格层面讲,对象是一系列可被使用的公共接口;
3 从概念层面讲,对象是某种拥有责任的抽象。
设计模式:架构方面、数据库方面、面向对象方面;
面向对象的两种思维模型
1 底层思维:如何机器底层,从微观理解对象构造。包括语言构造、编译转换、内存模型、运行时机制。
2 抽象思维:如何将我们周围的世界抽象成为程序代码。包括面向对象、组件封装、设计模式、架构模式。用来管理代码复杂度。
如何解决复杂度:
1 分解:人们面对复杂性有一个常见的做法:即分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单问题。
2 抽象:更高层次来讲,人们处理复杂性有一个通用的技术,即抽象。由于不能掌握全部的复杂对象,我们选择忽视它的非本质细节,而去处理泛化和理想化了的对象模型。
该系列主要总结了使用C++来实现各种设计模式,并结合实际的案例来分析如何使用,以及在什么场合下使用设计模式。以下是该系列所有文章的链接。希望对大家有帮助。
1 创建型(Creational)模式,将对象的部分创建工作 类或者其他对象,从而应对需求变化为对象创建
2 结构型(Structural)模式,
3 行为型(Behavioral)模式,
4 类模式处理类与子类的静态关系。
5 对象模式处理对象间的动态关系。
高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。
抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。
面向接口编程;(通过接口作为参数实现应用场景)
抽象就是接口或者抽象类,细节就是实现类
对扩展开放,对更改封闭。
类模块应该是可扩展的,但是不可修改。
用抽象构建架构,用实现扩展原则;/p>
一个类应该仅有一个引起它变化的原因。
变化的方向隐含着类的责任。
业务对象(BO business object)、业务逻辑(BL business logic)拆分;
子类可以扩展父类的功能,但不能改变原有父类的功能;
子类必须能够替换它们的基类(is-a)
继承表达类型抽象。
(目的:增强程序的健壮性)实际项目中,每个子类对应不同的业务含义,使父类作为参数,传递不同的子类完成不同的业务逻辑。
不应该强迫客户程序依赖它们不用的方法。
接口应该小而完备;
客户端不应该依赖它不需要的接口;
类之间依赖关系应该建立在最小的接口上;
接口的设计粒度越小,系统越灵活,但是灵活的同时结构复杂性提高,开发难度也会变大,维护性降低
类继承通常为“白箱复用”,对象组合通常为“黑箱复用”。
继承在某种程序上破坏了封装性,子类父类耦合度高。而对象组合则只要求组合的对象具有良好定义的接口。
使用封装来创建对象之间的分界层,让设计者可以在分界一侧进行修改,而不会对另一侧产生不良的影响,从而实现分界层之间的松耦合。
不将变量类型声明为某个特定的具体类,而是声明为某个接口。
客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案。
最少知道原则,尽量降低类与类之间的耦合;
一个对象应该对其他对象有最少的了解
软件设计模式的产生背景
“设计模式”这个术语最初并不是出现在软件设计中,而是被用于建筑领域的设计中。
1977 年,美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫·亚历山大(Christopher Alexander)在他的著作《建筑模式语言:城镇、建筑、构造(A Pattern Language: Towns Building Construction)中描述了一些常见的建筑设计问题,并提出了253种关于对城镇、邻里、住宅、花园和房间等进行设计的基本模式。
1979 年他的另一部经典著作《建筑的永恒之道》(The Timeless Way of Building)进一步强化了设计模式的思想,为后来的建筑设计指明了方向。
1987 年,肯特·贝克(Kent Beck)和沃德·坎宁安(Ward Cunningham)首先将克里斯托夫·亚历山大的模式思想应用在 Smalltalk 中的图形用户接口的生成中,但没有引起软件界的关注。
直到 1990 年,软件工程界才开始研讨设计模式的话题,后来召开了多次关于设计模式的研讨会。
1995 年,艾瑞克·伽马(ErichGamma)、理査德·海尔姆(Richard Helm)、拉尔夫·约翰森(Ralph Johnson)、约翰·威利斯迪斯(John Vlissides)等 4 位作者合作出版了《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)一书,在本教程中收录了 23 个设计模式,这是设计模式领域里程碑的事件,导致了软件设计模式的突破。这 4 位作者在软件开发领域里也以他们的“四人组”(Gang of Four,GoF)匿名著称。